package cc.catface.account;

import com.alibaba.csp.sentinel.SphO;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.alibaba.csp.sentinel.Entry;

@RestController
public class AccountController {

    @Value("${server.port}")
    private String port;

    @GetMapping("account")
    public String account() {
        return "account, server port:" + port + ", now:" + new Date().toLocaleString();
    }


    /**
     * ==========
     * sentinel *
     * ==========
     */
    /*定义资源*/
    //定义资源1/4(SphU)
    @GetMapping("xlSU")
    public String defineResourceBySphU() {
        Entry entry = null;
        try {
            entry = SphU.entry("defineResourceBySphU");
            return "定义资源by SphU方式(try-catch风格手动定义资源), port:" + port;
        } catch (BlockException e) {
            return "定义资源by SphU方式-服务被限流";
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }

    //定义资源2/4(SphO)
    @GetMapping("xlSO")
    public String defineResourceBySphO() {
        if (SphO.entry("defineResourceBySphO")) {
            try {
                return "定义资源by SphO方式(if-else风格手动定义资源), port:" + port;
            } finally {
                SphO.exit();
            }
        } else {
            return "定义资源by SphO方式-服务被限流";
        }
    }

    //定义资源3/4(注解)
    @GetMapping("xlAN")
    @SentinelResource(value = "defineResourceByAnn")
    public String defineResourceByAnn() {
        return "定义资源by 注解@SentinelResource方式(推荐), port:" + port;
    }

    /*限流(sentinel管理页限流方法为@SentinelResource内的value值[xlThisClass]而不是接口[/xlThis])*/
    //限流-方法在当前类
    @GetMapping("xlThis")
    @SentinelResource(value = "xlThisClass", blockHandler = "blockXlThisClass")
    public String xlThisClass() {
        return "限流(当前类), port:" + port;
    }

    public static String blockXlThisClass(BlockException exception) {
        return "限流(当前类)-服务被限流";
    }

    //限流-方法在其他类
    @GetMapping("xlOther")
    @SentinelResource(value = "xlOtherClass", blockHandlerClass = {BlockService.class}, blockHandler = "blockXlOtherClass")
    public String xlOtherClass() {
        return "限流(其他类), port:" + port;
    }

    //限流-限流规则代码定义
    @GetMapping("xlRule")
    @SentinelResource(value = "xlRuleDiy", blockHandler = "blockXlRuleDiy")
    public String xlRuleDiy() {
        initFlowRules();
        return "限流(代码定义限流规则), port:" + port;
    }

    public static String blockXlRuleDiy(BlockException exception) {
        return "限流(代码定义限流规则)-服务被限流";
    }

    /*代码定义限流规则*/
    private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("xlRuleDiy");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

}
